home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / c / nullmodem / src / modem.c < prev    next >
C/C++ Source or Header  |  1995-12-18  |  15KB  |  515 lines

  1. #include "defs.h"
  2. #include "protos.h"
  3.  
  4. #define MSG_OK              0
  5. #define MSG_CONNECT         1
  6. #define MSG_RING            2
  7. #define MSG_NO_CARRIER      3
  8. #define MSG_ERROR           4
  9. #define MSG_BUSY            5
  10.  
  11. char *speed[] = {
  12.         "",
  13.         " 103",
  14.         " V21",
  15.         " 300",
  16.         " 1200",
  17.         " 2400",
  18.         " 4800",
  19.         " 7200",
  20.         " 9600",
  21.         " 12000",
  22.         " 14400",
  23.         " 16800",
  24.         " 19200",
  25. };
  26.  
  27. char *protocol[] = {
  28.         "",
  29.         "/NONE",
  30.         "/SYNC",
  31.         "/REL",
  32.         "/REL-MNP",
  33.         "/REL-MNP-COMP",
  34.         "/REL-LAPM",
  35.         "/REL-LAPM-COMP",
  36.         "/V32",
  37.         "/ARQ",
  38.         "/ARQ/HST",
  39.         "/ARQ/HST/HST/V42BIS",
  40.         "/ARQ/HST/HST/MNP5",
  41.         "/ARQ/V32",
  42.         "/ARQ/V32/LAPM/V42BIS",
  43.         "/ARQ/V32/LAPM/MNP",
  44.         "/ARQ/V32/LAPM/MNP5",
  45.         "/ARQ/LAPM/V42BIS",
  46.         "/V42BIS",
  47. };
  48.  
  49. UBYTE S_Default[64] = {
  50.     0,   0, 020,   2, 012, 010,   0, 011,
  51.     0,   0,   1,   0,   0,   0,   0,   0,
  52.     0,   0,   0,   0,   0,   0,   0,   0,
  53.     0,   0,   0,   0,   0,   0,   0,   0,
  54.     0,   0,   0,   0,   0,   0,   0,   0,
  55.     0,   0,   0,   0,   0,   0,   0,   0,
  56.     0,   0,   0,   0,   0,   0,   0,   0,
  57.     0,   0,   0,   0,   0,   0,   0,   STATE_COMMAND,
  58. };
  59.  
  60.  
  61. /*
  62.  *  I am the Task. (Process, actually..)
  63.  */
  64. void
  65. modem_task(void)
  66. {
  67. struct NullModem *modem = FindTask(NULL)->tc_UserData;
  68. struct MsgPort *tport = &modem->nm_TimePort;
  69. struct timerequest *tr = &modem->nm_Timerequest;
  70. struct NullUnit *u0 = modem->nm_Unit[0];
  71. struct NullUnit *u1 = modem->nm_Unit[1];
  72.  
  73.     /* load the default S Register values */
  74.     S_Restore(modem->nm_Unit[0],1);
  75.     S_Restore(modem->nm_Unit[1],1);
  76.  
  77.     /* Initialise the timer port */
  78.     tport->mp_Node.ln_Type = NT_MSGPORT;
  79.     tport->mp_Flags = PA_SIGNAL;
  80.     tport->mp_SigBit = SIGBREAKB_CTRL_F;
  81.     tport->mp_SigTask = modem->nm_Taskptr;
  82.     NewList(&tport->mp_MsgList);
  83.  
  84.     /* Initialiase the timer request */
  85.     tr->tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  86.     tr->tr_node.io_Message.mn_ReplyPort = tport;
  87.     tr->tr_node.io_Command = TR_ADDREQUEST;
  88.  
  89.     /* start the 1s timer */
  90.     tr->tr_time.tv_secs = 1;
  91.     tr->tr_time.tv_micro = 0;
  92.     SendIO((struct IORequest *)tr);
  93.  
  94.     for(;;) {
  95.     ULONG mask = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F );
  96.  
  97.         ObtainSemaphore(&modem->nm_Semaphore);
  98.  
  99.         if( mask & SIGBREAKF_CTRL_E ) break;    /* Exit */
  100.  
  101.         if( mask & SIGBREAKF_CTRL_D ) {         /* Drop DTR */
  102.             if( u0->u_OpenCnt && u0->u_SReg[SREG_STATE] == STATE_CONNECTED ) {
  103.                 dprintf(u0, 2, "Disconnected\n");
  104.                 put_msg(u0, MSG_NO_CARRIER);
  105.                 u0->u_SReg[SREG_STATE] = STATE_COMMAND;
  106.                 u0->u_SReg[SREG_CMD_COUNT] = 0;
  107.             }
  108.  
  109.             if( u1->u_OpenCnt && u1->u_SReg[SREG_STATE] == STATE_CONNECTED ) {
  110.                 dprintf(u1, 2, "Disconnected\n");
  111.                 put_msg(u1, MSG_NO_CARRIER);
  112.                 u1->u_SReg[SREG_STATE] = STATE_COMMAND;
  113.                 u1->u_SReg[SREG_CMD_COUNT] = 0;
  114.             }
  115.         }
  116.  
  117.         if( mask & SIGBREAKF_CTRL_F ) {         /* Timer events */
  118.             GetMsg(tport);
  119.  
  120.             do_timer(u0,u1);
  121.             do_timer(u1,u0);
  122.  
  123.             tr->tr_time.tv_secs = 1;
  124.             tr->tr_time.tv_micro = 0;
  125.             SendIO((struct IORequest *)tr);
  126.         }
  127.  
  128.         if( mask & SIGBREAKF_CTRL_C ) {         /* Copy Data */
  129.             copy_data(u0, u1);
  130.             copy_data(u1, u0);
  131.         }
  132.  
  133.         ReleaseSemaphore(&modem->nm_Semaphore);
  134.     }
  135.  
  136.     AbortIO((struct IORequest *)tr);
  137.     WaitIO((struct IORequest *)tr);
  138.     CloseDevice((struct IORequest *)&modem->nm_Timerequest);
  139.  
  140.     Forbid();                               /* release memory/device etc */
  141.     DevBase->b_Lib.lib_OpenCnt--;
  142.     FreeMem(u0, sizeof(struct NullUnit));
  143.     FreeMem(u1, sizeof(struct NullUnit));
  144.     FreeMem(modem, sizeof(struct NullModem));
  145.  
  146.     /* fall off the end.. byebye! */
  147. }
  148.  
  149. /*
  150.  *  put_char() copies 1 char to a unit's buffer or readqueue
  151.  *
  152.  *  returns TRUE for success/FALSE for fail (buffer full)
  153.  */
  154. int
  155. put_char(struct NullUnit *unit, char c)
  156. {
  157. struct IOExtSer *iob = unit->u_Readlist.mlh_Head;
  158.  
  159.     /*
  160.      *  copy to any pending reads, else to the buffer
  161.      */
  162.     if( iob->IOSer.io_Message.mn_Node.ln_Succ ) {
  163.  
  164.         ((UBYTE *)iob->IOSer.io_Data)[iob->IOSer.io_Actual++] = c;
  165.  
  166.         if( iob->IOSer.io_Length == iob->IOSer.io_Actual ) {
  167.             Remove(&iob->IOSer.io_Message.mn_Node);
  168.             ReplyMsg(&iob->IOSer.io_Message);
  169.             dprintf(unit, 2, "read (%ld) complete\n",iob->IOSer.io_Length);
  170.         }
  171.     }
  172.     else if( unit->u_Bufcount < UNIT_BUF_SIZE ) {
  173.         unit->u_Bufcount++;
  174.         *unit->u_Writeptr-- = c;
  175.         if( unit->u_Writeptr < unit->u_Buffer )
  176.                 unit->u_Writeptr += UNIT_BUF_SIZE;
  177.     }
  178.     else
  179.         return(FALSE);
  180.  
  181.     return(TRUE);
  182. }
  183.  
  184. /*
  185.  *  puts a message string to the modem unit
  186.  */
  187. void
  188. put_str(struct NullUnit *unit, char *ptr)
  189. {
  190.     while( *ptr && put_char(unit, *ptr) ) ptr++;
  191. }
  192.  
  193. void
  194. put_msg(struct NullUnit *unit, int num)
  195. {
  196.     if( unit->u_SReg[SREG_NUMERIC] ) {
  197.         put_char(unit, '\r');
  198.         put_char(unit, '0' + num); /* limited to 10 result codes */
  199.         put_char(unit, '\r');
  200.     }
  201.     else {
  202.         put_str(unit, "\r\n");
  203.         switch( num ) {
  204.         case MSG_OK:
  205.                 put_str(unit, "OK");
  206.                 break;
  207.         case MSG_CONNECT:
  208.                 put_str(unit, "CONNECT");
  209.                 put_str(unit, speed[unit->u_SReg[SREG_SPEED] >= (sizeof(speed)/sizeof(*speed)) ? 0 : unit->u_SReg[SREG_SPEED]]);
  210.                 put_str(unit, protocol[unit->u_SReg[SREG_PROTOCOL] >= (sizeof(protocol)/sizeof(*protocol)) ? 0 : unit->u_SReg[SREG_PROTOCOL]]);
  211.                 break;
  212.         case MSG_RING:
  213.                 put_str(unit, "RING");
  214.                 break;
  215.         case MSG_NO_CARRIER:
  216.                 put_str(unit, "NO CARRIER");
  217.                 break;
  218.         case MSG_ERROR:
  219.                 put_str(unit, "ERROR");
  220.                 break;
  221.         case MSG_BUSY:
  222.                 put_str(unit, "BUSY");
  223.                 break;
  224.         }
  225.         put_str(unit, "\r\n");
  226.     }
  227. }
  228.  
  229. void
  230. do_command(struct NullUnit *unit)
  231. {
  232. char *p = unit->u_Command;
  233. int count = unit->u_SReg[SREG_CMD_COUNT];
  234.  
  235.     unit->u_SReg[SREG_CMD_COUNT] = 0;
  236.  
  237.     if( count-- && (*p == 'A' || *p == 'a') ) {
  238.         p++;
  239.         if( count-- && (*p == 'T' || *p == 't') ) {
  240.             p++;
  241.             while( count-- ) {
  242.                 switch(*p++) {
  243.                 case 'a':
  244.                 case 'A':
  245.                     unit->u_SReg[SREG_STATE] = STATE_ANSWERING;
  246.                     unit->u_SReg[SREG_ANSWERING] = unit->u_SReg[SREG_DELAY];
  247.                     unit->u_SReg[SREG_RINGS] = 0;
  248.                     return;
  249.                 case 'd':
  250.                 case 'D':
  251.                     unit->u_SReg[SREG_STATE] = STATE_DIALING;
  252.                     unit->u_SReg[SREG_RINGS] = unit->u_SReg[SREG_TIMEOUT];
  253.                     unit->u_SReg[SREG_ANSWERING] = 0;
  254.                     return;
  255.                 case 'z':
  256.                 case 'Z':
  257.                     S_Restore(unit,1);
  258.                     break;
  259.                 case 'f':
  260.                 case 'F':
  261.                     S_Restore(unit,0);
  262.                     break;
  263.                 case 'w':
  264.                 case 'W':
  265.                     S_Save(unit);
  266.                     break;
  267.                 case 'l':
  268.                 case 'L':
  269.                     {
  270.                     extern char ID[];
  271.                     UBYTE i = 0;
  272.  
  273.                         put_str(unit, "\r\n");
  274.                         put_str(unit, ID);
  275.                         while( i < 8 ) {
  276.                         UBYTE j = 0;
  277.  
  278.                             while( j < 8 ) {
  279.                             UBYTE s = unit->u_SReg[(i << 3) + j];
  280.  
  281.                                 put_char(unit,i+'0');
  282.                                 put_char(unit,j+'0');
  283.                                 put_char(unit,':');
  284.                                 put_char(unit,((s >> 6) & 0x7) + '0');
  285.                                 put_char(unit,((s >> 3) & 0x7) + '0');
  286.                                 put_char(unit,((s >> 0) & 0x7) + '0');
  287.                                 put_char(unit,' ');
  288.                                 put_char(unit,' ');
  289.  
  290.                                 j++;
  291.                             }
  292.  
  293.                             put_char(unit,'\r');
  294.                             put_char(unit,'\n');
  295.                             i++;
  296.                         }
  297.                     }
  298.                     break;
  299.                 case 's':
  300.                 case 'S':
  301.                     {
  302.                     int reg = 0, value = 0;
  303.  
  304.                         while( count && *p >= '0' && *p <= '7' ) {
  305.                             reg = (reg << 3) + (*p - '0');
  306.                             p++, count--;
  307.                         }
  308.  
  309.                         if( count && *p == '=' ) p++,count--;
  310.                         else {
  311.                             put_msg(unit, MSG_ERROR);
  312.                             return;
  313.                         }
  314.  
  315.                         while( count && *p >= '0' && *p <= '7' ) {
  316.                             value = (value << 3) + (*p - '0');
  317.                             p++, count--;
  318.                         }
  319.  
  320.                         unit->u_SReg[reg & 0x3f] = value & 0xff;
  321.                     }
  322.                     break;
  323.                 default:
  324.                     put_msg(unit, MSG_ERROR);
  325.                     return;
  326.                 }
  327.             }
  328.             put_msg(unit, MSG_OK);
  329.         }
  330.     }
  331. }
  332.  
  333. /*
  334.  *  copy_data()  processes writes that may be waiting at the unit
  335.  *
  336.  *      arguments:  unit is the unit to process from
  337.  *                  other is the unit to write to, if connected
  338.  */
  339. void
  340. copy_data(struct NullUnit *unit, struct NullUnit *other)
  341. {
  342. struct IOExtSer *temp, *iob = unit->u_Writelist.mlh_Head;
  343.  
  344.     /*
  345.      *  for each write request in the queue..
  346.      */
  347.     while( temp = iob->IOSer.io_Message.mn_Node.ln_Succ ) {
  348.     UBYTE *data = (UBYTE *)iob->IOSer.io_Data + iob->IOSer.io_Actual;
  349.     unsigned int count = iob->IOSer.io_Length - iob->IOSer.io_Actual;
  350.  
  351.         /*
  352.          *  copy the data from this write request to the writeunit
  353.          */
  354.         if( unit->u_SReg[SREG_STATE] == STATE_CONNECTED ) {
  355.             while( count ) {
  356.                 if( !put_char(other, *data) ) break;
  357.                 count--;
  358.                 data++;
  359.             }
  360.         }
  361.         else {  /* or else do local command line stuff */
  362.             while( count ) {
  363.                 if( unit->u_SReg[SREG_STATE] != STATE_COMMAND ) {
  364.                     if( *data != '\n' ) {
  365.                         unit->u_SReg[SREG_STATE] = STATE_COMMAND;
  366.                         unit->u_SReg[SREG_CMD_COUNT] = 0;
  367.                         put_msg(unit, MSG_NO_CARRIER);
  368.                     }
  369.                 }
  370.  
  371.                 if( unit->u_SReg[SREG_LOCALECHO] && !put_char(unit, *data) ) break;
  372.  
  373.                 if( unit->u_SReg[SREG_STATE] == STATE_COMMAND ) {
  374.                     if( *data != '\n' ) {
  375.                         if( *data == unit->u_SReg[SREG_BACKSPACE] ) {
  376.                             if( unit->u_SReg[SREG_CMD_COUNT] )
  377.                                     unit->u_SReg[SREG_CMD_COUNT] -= 1;
  378.                         }
  379.                         else if( *data != '\r' ) {
  380.                             if( unit->u_SReg[SREG_CMD_COUNT] < 256 ) {
  381.                                 unit->u_Command[unit->u_SReg[SREG_CMD_COUNT]] = *data;
  382.                                 unit->u_SReg[SREG_CMD_COUNT]++;
  383.                             }
  384.                         }
  385.                         else
  386.                             do_command(unit);
  387.                     }
  388.                 }
  389.  
  390.                 count--;
  391.                 data++;
  392.             }
  393.         }
  394.  
  395.         iob->IOSer.io_Actual = iob->IOSer.io_Length - count;
  396.  
  397.         if( count ) break; /* no point continuing if there was no room */
  398.  
  399.         /*
  400.          *  Request satisfied, go on to the next one..
  401.          */
  402.         Remove(&iob->IOSer.io_Message.mn_Node);
  403.         ReplyMsg(&iob->IOSer.io_Message);
  404.         dprintf(unit, 3, "write (%ld) complete\n",iob->IOSer.io_Length);
  405.         iob = temp;
  406.     }
  407. }
  408.  
  409. void
  410. do_connect(struct NullUnit *u0, struct NullUnit *u1)
  411. {
  412.     u0->u_SReg[SREG_STATE] = STATE_CONNECTED;
  413.     put_msg(u0, MSG_CONNECT);
  414.  
  415.     u1->u_SReg[SREG_STATE] = STATE_CONNECTED;
  416.     put_msg(u1, MSG_CONNECT);
  417. }
  418.  
  419. /* Ugh -- Clean Me Up! */
  420. void
  421. do_timer(struct NullUnit *unit, struct NullUnit *other)
  422. {
  423.     if( unit->u_SReg[SREG_STATE] == STATE_DIALING ) {
  424.         if( unit->u_SReg[SREG_RINGS] ) {
  425.             if( other->u_OpenCnt ) {
  426.                 if( other->u_SReg[SREG_STATE] == STATE_ANSWERING ) {
  427.                     if( other->u_SReg[SREG_ANSWERING] == 0 ) {
  428.                         do_connect(unit,other);
  429.                     }
  430.                 }
  431.                 else {
  432.                     unit->u_SReg[SREG_RINGS] -= 1;
  433.                     if( (unit->u_SReg[SREG_TIMEOUT] - unit->u_SReg[SREG_RINGS]) == other->u_SReg[SREG_ANSWER] ) {
  434.                         do_connect(unit,other);
  435.                     }
  436.                     else {
  437.                         put_msg(other, MSG_RING);
  438.                         dprintf(other,2,"Ring\n");
  439.                     }
  440.                 }
  441.             }
  442.             else {
  443.                 put_msg(unit, MSG_BUSY);
  444.                 unit->u_SReg[SREG_RINGS] = 0;
  445.                 unit->u_SReg[SREG_STATE] = STATE_COMMAND;
  446.             }
  447.         }
  448.         else {
  449.             put_msg(unit, MSG_NO_CARRIER);
  450.             unit->u_SReg[SREG_STATE] = STATE_COMMAND;
  451.         }
  452.     }
  453.     else if( unit->u_SReg[SREG_STATE] == STATE_ANSWERING ) {
  454.         if( unit->u_SReg[SREG_ANSWERING] == 0 ) {
  455.             put_msg(unit, MSG_NO_CARRIER);
  456.             unit->u_SReg[SREG_STATE] = STATE_COMMAND;
  457.         }
  458.         else {
  459.             unit->u_SReg[SREG_ANSWERING] -= 1;
  460.         }
  461.     }
  462. }
  463.  
  464. /*
  465.  *  Save/Restore the S Registers from ENV:nullmodemX.config
  466.  *                                                 X is unit number
  467.  */
  468.  
  469. const UBYTE vputch[] = { 0x16, 0xc0, 0x4e, 0x75 }; /* move.b d0,(a3)+ rts */
  470.  
  471. char *varname(UWORD unitnum)
  472. {
  473. static char buffer[32];
  474.  
  475.     RawDoFmt("nullmodem%d.config",&unitnum,(void (*)())vputch,buffer);
  476.  
  477.     return(buffer);
  478. }
  479.  
  480. S_Restore(struct NullUnit *unit, int load)
  481. {
  482. UBYTE Temp[65];
  483. LONG len = 0;
  484.  
  485.     if( load ) {
  486.     struct Library *DOSBase;
  487.  
  488.         if( DOSBase = OpenLibrary("dos.library",36) ) {
  489.             len = GetVar(varname(unit->u_Unitnum), Temp, 65, GVF_BINARY_VAR);
  490.             CloseLibrary(DOSBase);
  491.         }
  492.     }
  493.  
  494.     if( len == 64 ) {
  495.     int i;
  496.  
  497.         for( i = 0 ; i < 64 ; i++ ) unit->u_SReg[i] = Temp[i];
  498.     }
  499.     else {
  500.     int i;
  501.  
  502.         for( i = 0 ; i < 64 ; i++ ) unit->u_SReg[i] = S_Default[i];
  503.     }
  504. }
  505.  
  506. S_Save(struct NullUnit *unit)
  507. {
  508. struct Library *DOSBase = OpenLibrary("dos.library",36);
  509.  
  510.     if( DOSBase ) {
  511.         SetVar(varname(unit->u_Unitnum), unit->u_SReg, 64, GVF_GLOBAL_ONLY);
  512.         CloseLibrary(DOSBase);
  513.     }
  514. }
  515.